home *** CD-ROM | disk | FTP | other *** search
/ The Very Best of Atari Inside / The Very Best of Atari Inside 1.iso / mint / mint110s / filesys.c < prev    next >
C/C++ Source or Header  |  1994-02-02  |  33KB  |  1,281 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith.
  3. Copyright 1992,1993,1994 Atari Corp.
  4. All rights reserved.
  5. */
  6.  
  7. /*
  8.  * various file system interface things
  9.  */
  10.  
  11. #include "mint.h"
  12.  
  13. #define PATH2COOKIE_DB(x) TRACE(x)
  14.  
  15. FILESYS *active_fs;
  16. FILESYS *drives[NUM_DRIVES];
  17. extern FILESYS tos_filesys;    /* declaration needed for debugging only */
  18.  
  19. /* "aliased" drives are different names
  20.  * for real drives/directories
  21.  * if drive d is an alias for c:\usr,
  22.  * then alias_drv[3] == 2 (the real
  23.  * drive) and aliases has bit (1L << 3)
  24.  * set.
  25.  * NOTE: if aliasdrv[d] is 0, then d is not an aliased drive,
  26.  * otherwise d is aliased to drive aliasdrv[d]-1
  27.  * (e.g. if drive A: is aliased to B:\FOO, then
  28.  * aliasdrv[0] == 'B'-'A'+1 == 2). Always remember to
  29.  * compensate for the extra 1 when dereferencing aliasdrv!
  30.  */
  31. int    aliasdrv[NUM_DRIVES];
  32.  
  33. FILEPTR *flist;        /* a list of free file pointers */
  34.  
  35. char follow_links[1];    /* dummy "name" used as a parameter to path2cookie */
  36.  
  37. /* vector of valid drives, according to GEMDOS */
  38. /* note that this isn't necessarily the same as what the BIOS thinks of
  39.  * as valid
  40.  */
  41. long dosdrvs;
  42.  
  43. /*
  44.  * Initialize a specific drive. This is called whenever a new drive
  45.  * is accessed, or when media change occurs on an old drive.
  46.  * Assumption: at this point, active_fs is a valid pointer
  47.  * to a list of file systems.
  48.  */
  49.  
  50. /* table of processes holding locks on drives */
  51. extern PROC *dlockproc[];    /* in dosdir.c */
  52.  
  53. void
  54. init_drive(i)
  55.     int i;
  56. {
  57.     long r;
  58.     FILESYS *fs;
  59.     fcookie root_dir;
  60.  
  61.     TRACE(("init_drive(%c)", i+'A'));
  62.  
  63.     drives[i] = 0;        /* no file system */
  64.     if (i >= 0 && i < NUM_DRIVES) {
  65.         if (dlockproc[i]) return;
  66.     }
  67.  
  68.     for (fs = active_fs; fs; fs = fs->next) {
  69.         r = (*fs->root)(i, &root_dir);
  70.         if (r == 0) {
  71.             drives[i] = root_dir.fs;
  72.             release_cookie(&root_dir);
  73.             break;
  74.         }
  75.     }
  76. }
  77.  
  78. /*
  79.  * initialize the file system
  80.  */
  81.  
  82. #define NUMFPS    40    /* initial number of file pointers */
  83.  
  84. void
  85. init_filesys()
  86. {
  87.     static FILEPTR initial[NUMFPS+1];
  88.     int i;
  89.     extern FILESYS tos_filesys, bios_filesys, pipe_filesys,
  90.         proc_filesys, uni_filesys;
  91.  
  92. /* get the vector of connected GEMDOS drives */
  93.     dosdrvs = Dsetdrv(Dgetdrv()) | drvmap();
  94.  
  95. /* set up some initial file pointers */
  96.     for (i = 0; i < NUMFPS; i++) {
  97.         initial[i].devinfo = (ulong) (&initial[i+1]);
  98.     }
  99.     initial[NUMFPS].devinfo = 0;
  100.     flist = initial;
  101.  
  102. /* set up the file systems */
  103.     tos_filesys.next = 0;
  104.     bios_filesys.next = &tos_filesys;
  105.     pipe_filesys.next = &bios_filesys;
  106.     proc_filesys.next = &pipe_filesys;
  107.     uni_filesys.next = &proc_filesys;
  108.  
  109.     active_fs = &uni_filesys;
  110.  
  111. /* initialize the BIOS file system */
  112.     biosfs_init();
  113.  
  114. /* initialize the unified file system */
  115.     unifs_init();
  116. }
  117.  
  118. /*
  119.  * load file systems from disk
  120.  * this routine is called after process 0 is set up, but before any user
  121.  * processes are run
  122.  *
  123.  * NOTE that a number of directory changes take place here: we look first
  124.  * in the current directory, then in the directory \mint.
  125.  */
  126.  
  127. typedef FILESYS * ARGS_ON_STACK (*FSFUNC) P_((struct kerinfo *));
  128.  
  129. /* uk: made this lie outside of functions, as load_filesys() and
  130.  *     load_devdriver() need access to it.
  131.  */
  132. #define NPATHS 3
  133. static const char *ext_paths[NPATHS] = {"", "\\MINT", "\\MULTITOS"};
  134.  
  135.  
  136. void
  137. load_filesys()
  138. {
  139.     long r;
  140.     BASEPAGE *b;
  141.     FILESYS *fs;
  142.     FSFUNC initf;
  143.     static DTABUF dta;
  144.     int i;
  145.     extern struct kerinfo kernelinfo; /* in main.c */
  146.     char curpath[PATH_MAX];
  147.     MEMREGION *xfsreg;
  148.  
  149.     curproc->dta = &dta;
  150.     d_getpath(curpath,0);
  151.  
  152.     for (i = 0; i < NPATHS; i++) {
  153.         if (*ext_paths[i]) {
  154. /* don't bother checking the current directory twice! */
  155.             if (!stricmp(ext_paths[i],curpath))
  156.             r = -1;
  157.             else
  158.             r = d_setpath(ext_paths[i]);
  159.         }
  160.         else
  161.             r = 0;
  162.  
  163.         if (r == 0)
  164.             r = f_sfirst("*.xfs", 0);
  165.  
  166.         while (r == 0) {
  167.         b = (BASEPAGE *)p_exec(3, dta.dta_name, (char *)"", (char *)0);
  168.         if ( ((long)b) < 0 ) {
  169.             DEBUG(("Error loading file system %s", dta.dta_name));
  170.             r = f_snext();
  171.             continue;
  172.         }
  173.     /* we leave a little bit of slop at the end of the loaded stuff */
  174.         m_shrink(0, (virtaddr)b, 512 + b->p_tlen + b->p_dlen + b->p_blen);
  175.         initf = (FSFUNC)b->p_tbase;
  176.         TRACE(("initializing %s", dta.dta_name));
  177.         fs = (*initf)(&kernelinfo);
  178.  
  179.         if (fs) {
  180.             TRACE(("%s loaded OK", dta.dta_name));
  181.     /* put the loaded XFS into super accesible memory */
  182.             xfsreg = addr2region( (long) b );
  183.             mark_region(xfsreg, PROT_S);
  184.  
  185.     /* link it into the list of drivers */
  186.     /* uk: but only if it has not installed itself via Dcntl()
  187.      *     after checking if file system is already installed,
  188.      *     so we know for sure that each file system in at most
  189.      *     once in the chain (important for removal!)
  190.      * also note: this doesn't preclude loading two different
  191.      * instances of the same file system driver, e.g. it's perfectly
  192.      * OK to have a "cdromy1.xfs" and "cdromz2.xfs"; the check below
  193.      * just makes sure that a given instance of a file system is
  194.      * installed at most once. I.e., it prevents cdromy1.xfs from being
  195.      * installed twice.
  196.      */
  197.             if ((FILESYS*)1L != fs) {
  198.                 FILESYS *f = active_fs;
  199.                 for (;  f;  f = f->next)
  200.                     if (f == fs)
  201.                         break;
  202.                 if (!f) {   /* we ran completly through the list */
  203.                     fs->next = active_fs;
  204.                     active_fs = fs;
  205.                 }
  206.             }
  207.         } else {
  208.             DEBUG(("%s returned null", dta.dta_name));
  209.             m_free((virtaddr)b);
  210.         }
  211.         r = f_snext();
  212.         }
  213.     }
  214.  
  215. #if 0
  216. /* here, we invalidate all old drives EXCEPT for ones we're already using (at
  217.  * this point, only the bios devices should be open)
  218.  * this gives newly loaded file systems a chance to replace the
  219.  * default tosfs.c
  220.  */
  221.     for (i = 0; i < NUM_DRIVES; i++) {
  222.         if (d_lock(1, i) == 0)    /* lock if possible */
  223.             d_lock(0, i);    /* and then unlock */
  224.     }
  225. #endif
  226. }
  227.  
  228.  
  229. /*
  230.  * uk: load device driver in files called *.xdd (external device driver)
  231.  *     from disk
  232.  * maybe this should go into biosfs.c ??
  233.  *
  234.  * this routine is called after process 0 is set up, but before any user
  235.  * processes are run, but before the loadable file systems come in,
  236.  * so they can make use of external device drivers
  237.  *
  238.  * NOTE that a number of directory changes take place here: we look first
  239.  * in the current directory, then in the directory \mint, and finally
  240.  * the d_lock() calls force us into the root directory.
  241.  * ??? what d_lock() calls ???
  242.  */
  243.  
  244. typedef DEVDRV * ARGS_ON_STACK (*DEVFUNC) P_((struct kerinfo *));
  245.  
  246. #define DEV_SELFINST  ((DEVDRV*)1L)  /* dev driver did dcntl() already */
  247.  
  248. void
  249. load_devdriver()
  250. {
  251.     long r;
  252.     BASEPAGE *b;
  253.     DEVDRV *dev;
  254.     DEVFUNC initf;
  255.     struct dev_descr the_dev;
  256.     static DTABUF dta;
  257.     int i;
  258.     extern struct kerinfo kernelinfo; /* in main.c */
  259.     char curpath[PATH_MAX];
  260.     char dev_name[PATH_MAX];  /* a bit long, but one never knows... */
  261.     char ch, *p;
  262.     MEMREGION *xddreg;
  263.  
  264.  
  265.     curproc->dta = &dta;
  266.     d_getpath(curpath,0);
  267.  
  268.     for (i = 0; i < NPATHS; i++) {
  269.         if (*ext_paths[i]) {
  270. /* don't bother checking the current directory twice! */
  271.             if (!stricmp(ext_paths[i],curpath))
  272.             r = -1;
  273.             else
  274.             r = d_setpath(ext_paths[i]);
  275.         }
  276.         else
  277.             r = 0;
  278.  
  279.         if (r == 0)
  280.             r = f_sfirst("*.xdd", 0);
  281.  
  282.         while (r == 0) {
  283.         b = (BASEPAGE *)p_exec(3, dta.dta_name, (char *)"", (char *)0);
  284.         if ( ((long)b) < 0 ) {
  285.             DEBUG(("Error loading device driver %s", dta.dta_name));
  286.             r = f_snext();
  287.             continue;
  288.         }
  289.     /* we leave a little bit of slop at the end of the loaded stuff */
  290.         m_shrink(0, (virtaddr)b, 512 + b->p_tlen + b->p_dlen + b->p_blen);
  291.         initf = (DEVFUNC)b->p_tbase;
  292.         TRACE(("initializing %s", dta.dta_name));
  293.         dev = (*initf)(&kernelinfo);
  294.  
  295.         if (dev) {
  296.             if (DEV_SELFINST != dev) {
  297.     /* we need to install the device driver ourselves */
  298.                 the_dev.driver = dev;
  299.                 the_dev.dinfo = 0;
  300.                 the_dev.flags = 0;
  301.                 the_dev.tty = (struct tty*)0L;
  302.                 the_dev.reserved[0] = the_dev.reserved[1] = 0;
  303.                 the_dev.reserved[2] = the_dev.reserved[3] = 0;
  304.                 p = dta.dta_name;
  305.     /* copy the dev. driver name, converting to lower case */
  306.                 while (*p && *p != '.') {
  307.                     *p = tolower(*p);
  308.                     p++;
  309.                 }
  310.                 ch = *p;
  311.                 *p = '\0';  /* we dont want the extension */
  312.                 strcpy(dev_name, "u:\\dev\\");
  313.                 strcat(dev_name, dta.dta_name);
  314.                 *p = ch;
  315.                 r = d_cntl(DEV_INSTALL, dev_name, (long)&the_dev);
  316.                 if (r <= 0) {
  317.                     DEBUG(("Error installing device driver %s", dta.dta_name));
  318.                     r = f_snext();
  319.                     continue;
  320.                 }
  321.             }
  322.             TRACE(("%s loaded OK", dta.dta_name));
  323.     /* put the loaded XDD into super accesible memory */
  324.             xddreg = addr2region( (long) b );
  325.             mark_region(xddreg, PROT_S);
  326.         } else {
  327.             DEBUG(("%s returned null", dta.dta_name));
  328.             m_free((virtaddr)b);
  329.         }
  330.         r = f_snext();
  331.         }
  332.     }
  333. }
  334.  
  335.  
  336. void
  337. close_filesys()
  338. {
  339.     PROC *p;
  340.     FILEPTR *f;
  341.     int i;
  342.  
  343.     TRACE(("close_filesys"));
  344. /* close every open file */
  345.     for (p = proclist; p; p = p->gl_next) {
  346.         for (i = MIN_HANDLE; i < MAX_OPEN; i++) {
  347.             if ( (f = p->handle[i]) != 0) {
  348.                 if (p->wait_q == TSR_Q || p->wait_q == ZOMBIE_Q)
  349.                     ALERT("Open file for dead process?");
  350.                 do_pclose(p, f);
  351.             }
  352.         }
  353.     }
  354. }
  355.  
  356. /*
  357.  * "media change" routine: called when a media change is detected on device
  358.  * d, which may or may not be a BIOS device. All handles associated with
  359.  * the device are closed, and all directories invalidated. This routine
  360.  * does all the dirty work, and is called automatically when
  361.  * disk_changed detects a media change.
  362.  */
  363.  
  364. void ARGS_ON_STACK 
  365. changedrv(d)
  366.     unsigned d;
  367. {
  368.     PROC *p;
  369.     int i;
  370.     FILEPTR *f;
  371.     FILESYS *fs;
  372.     SHTEXT *stext;
  373.     extern SHTEXT *text_reg;    /* in mem.c */
  374.     DIR *dirh;
  375.     fcookie dir;
  376.     int warned = (d & 0xf000) == PROC_RDEV_BASE;
  377.     long r;
  378.  
  379. /* if an aliased drive, change the *real* device */
  380.     if (d < NUM_DRIVES && aliasdrv[d]) {
  381.         d = aliasdrv[d] - 1;    /* see NOTE above */
  382.     }
  383.  
  384. /* re-initialize the device, if it was a BIOS device */
  385.     if (d < NUM_DRIVES) {
  386.         fs = drives[d];
  387.         if (fs) {
  388.             (void)(*fs->dskchng)(d);
  389.         }
  390.         init_drive(d);
  391.     }
  392.  
  393.     for (p = proclist; p; p = p->gl_next) {
  394.     /* invalidate all open files on this device */
  395.         for (i = MIN_HANDLE; i < MAX_OPEN; i++) {
  396.             if (((f = p->handle[i]) != 0) && (f->fc.dev == d)) {
  397.                 if (!warned) {
  398.                 ALERT(
  399. "Files were open on a changed drive (0x%x)!", d);
  400.                 warned++;
  401.                 }
  402.  
  403. /* we set f->dev to NULL to indicate to do_pclose that this is an
  404.  * emergency close, and that it shouldn't try to make any
  405.  * calls to the device driver since the file has gone away
  406.  */
  407.                 f->dev = NULL;
  408.                 (void)do_pclose(p, f);
  409. /* we could just zero the handle, but this could lead to confusion if
  410.  * a process doesn't realize that there's been a media change, Fopens
  411.  * a new file, and gets the same handle back. So, we force the
  412.  * handle to point to /dev/null.
  413.  */
  414.                 p->handle[i] =
  415.                 do_open("U:\\DEV\\NULL", O_RDWR, 0, (XATTR *)0);
  416.             }
  417.         }
  418.  
  419.     /* terminate any active directory searches on the drive */
  420.         for (i = 0; i < NUM_SEARCH; i++) {
  421.             dirh = &p->srchdir[i];
  422.             if (p->srchdta[i] && dirh->fc.fs && dirh->fc.dev == d) {
  423.                 TRACE(("closing search for process %d", p->pid));
  424.                 release_cookie(&dirh->fc);
  425.                 dirh->fc.fs = 0;
  426.                 p->srchdta[i] = 0;
  427.             }
  428.         }
  429.  
  430.         for (dirh = p->searches; dirh; dirh = dirh->next) {
  431.             /* If this search is on the changed drive, release
  432.                the cookie, but do *not* free it, since the
  433.                user could later call closedir on it. */
  434.             if (dirh->fc.fs && dirh->fc.dev == d) {
  435.                 release_cookie (&dirh->fc);
  436.                 dirh->fc.fs = 0;
  437.             }
  438.         }
  439.             
  440.         if (d >= NUM_DRIVES) continue;
  441.  
  442.     /* change any active directories on the device to the (new) root */
  443.         fs = drives[d];
  444.         if (fs) {
  445.             r = (*fs->root)(d, &dir);
  446.             if (r != E_OK) dir.fs = 0;
  447.         } else {
  448.             dir.fs = 0; dir.dev = d;
  449.         }
  450.  
  451.         for (i = 0; i < NUM_DRIVES; i++) {
  452.             if (p->root[i].dev == d) {
  453.                 release_cookie(&p->root[i]);
  454.                 dup_cookie(&p->root[i], &dir);
  455.             }
  456.             if (p->curdir[i].dev == d) {
  457.                 release_cookie(&p->curdir[i]);
  458.                 dup_cookie(&p->curdir[i], &dir);
  459.             }
  460.         }
  461.         release_cookie(&dir);
  462.     }
  463.  
  464. /* free any file descriptors associated with shared text regions */
  465.     for (stext = text_reg; stext; stext = stext->next) {
  466.         f = stext->f;
  467.         if (f->fc.dev == d) {
  468.             f->dev = NULL;
  469.             do_pclose(rootproc, f);
  470.             stext->f = 0;
  471.         }
  472.     }
  473. }
  474.  
  475. /*
  476.  * check for media change: if the drive has changed, call changedrv to
  477.  * invalidate any open files and file handles associated with it, and
  478.  * call the file system's media change routine.
  479.  * returns: 0 if no change, 1 if change, negative number for error
  480.  */
  481.  
  482. int
  483. disk_changed(d)
  484.     int d;
  485. {
  486.     short r;
  487.     FILESYS *fs;
  488.     static char tmpbuf[8192];
  489.  
  490. /* for now, only check BIOS devices */
  491.     if (d < 0 || d >= NUM_DRIVES)
  492.         return 0;
  493. /* watch out for aliased drives */
  494.     if (aliasdrv[d]) {
  495.         d = aliasdrv[d] - 1;
  496.         if (d < 0 || d >= NUM_DRIVES)
  497.             return 0;
  498.     }
  499.  
  500. /* has the drive been initialized yet? If not, then initialize it and return
  501.  * "no change"
  502.  */
  503.     fs = drives[d];
  504.     if (!fs) {
  505.         TRACE(("drive %c not yet initialized", d+'A'));
  506.         changedrv(d);
  507.         return 0;
  508.     }
  509.  
  510. /* We have to do this stuff no matter what, because someone may have installed
  511.  * vectors to force a media change...
  512.  * PROBLEM: AHDI may get upset if the drive isn't valid.
  513.  * SOLUTION: don't change the default PSEUDODRIVES setting!
  514.  */
  515.  
  516. TRACE(("calling mediach(%d)",d));
  517.     r = (int)mediach(d);
  518. TRACE(("mediach(%d) == %d", d, r));
  519.  
  520.     if (r < 0) {
  521. /* KLUDGE: some .XFS drivers don't install BIOS vectors, and so we'll
  522.  * always get EUNDEV back from them. This isn't recommended (since there
  523.  * are other programs than MiNT that may ask for BIOS functions from
  524.  * any installed drives). This is a temporary work-around until those
  525.  * .XFSes are changed to either install BIOS vectors or to use the
  526.  * new U: Dcntl() calls to install themselves.
  527.  * Note that EUNDEV must be tested for drives A-C, or else booting may
  528.  * not work properly.
  529.  */
  530.         if (d > 2 && r == EUNDEV)
  531.             r = 2;        /* assume there may be a change */
  532.         else
  533.             return r;
  534.     }
  535.     if (r == 1) {        /* drive _may_ have changed */
  536.         r = rwabs(0, tmpbuf, 1, 0, d, 0L);    /* check the BIOS */
  537.         if (r != E_CHNG) {            /* nope, no change */
  538.             TRACE(("rwabs returned %d", r));
  539.             return (r < 0) ? r : 0;
  540.         }
  541.         r = 2;            /* drive was definitely changed */
  542.     }
  543.     if (r == 2) {
  544.         TRACE(("definite media change"));
  545.         fs = drives[d];        /* get filesystem associated with drive */
  546.         if ((*fs->dskchng)(d)) { /* does the fs agree that it changed? */
  547.             drives[d] = 0;
  548.             changedrv(d);    /* yes -- do the change */
  549.             return 1;
  550.         }
  551.     }
  552.     return 0;
  553. }
  554.  
  555. /*
  556.  * routines for parsing path names
  557.  */
  558.  
  559. #define DIRSEP(p) ((p) == '\\')
  560.  
  561. /*
  562.  * relpath2cookie converts a TOS file name into a file cookie representing
  563.  * the directory the file resides in, and a character string representing
  564.  * the name of the file in that directory. The character string is
  565.  * copied into the "lastname" array. If lastname is NULL, then the cookie
  566.  * returned actually represents the file, instead of just the directory
  567.  * the file is in.
  568.  *
  569.  * note that lastname, if non-null, should be big enough to contain all the
  570.  * characters in "path", since if the file system doesn't want the kernel
  571.  * to do path name parsing we may end up just copying path to lastname
  572.  * and returning the current or root directory, as appropriate
  573.  *
  574.  * "relto" is the directory relative to which the search should start.
  575.  * if you just want the current directory, use path2cookie instead.
  576.  *
  577.  */
  578.  
  579. #define MAX_LINKS 4
  580.  
  581. long
  582. relpath2cookie(relto, path, lastname, res, depth)
  583.     fcookie *relto;
  584.     const char *path;
  585.     char *lastname;
  586.     fcookie *res;
  587.     int depth;
  588. {
  589.     fcookie dir;
  590.     int drv;
  591.     int len;
  592.     char c, *s;
  593.     XATTR xattr;
  594.     static char newpath[16] = "U:\\DEV\\";
  595.     char temp2[PATH_MAX];
  596.     char linkstuff[PATH_MAX];
  597.     long r;
  598.  
  599. /* dolast: 0 == return a cookie for the directory the file is in
  600.  *         1 == return a cookie for the file itself, don't follow links
  601.  *       2 == return a cookie for whatever the file points at
  602.  */
  603.     int dolast = 0;
  604.     int i = 0;
  605.  
  606.     if (!lastname) {
  607.         dolast = 1;
  608.         lastname = temp2;
  609.     } else if (lastname == follow_links) {
  610.         dolast = 2;
  611.         lastname = temp2;
  612.     }
  613.  
  614.     *lastname = 0;
  615.  
  616. PATH2COOKIE_DB(("relpath2cookie(%s, dolast=%d, depth=%d)", path, dolast, depth));
  617.  
  618.     if (depth > MAX_LINKS) {
  619.         DEBUG(("Too many symbolic links"));
  620.         return ELOOP;
  621.     }
  622. /* special cases: CON:, AUX:, etc. should be converted to U:\DEV\CON,
  623.  * U:\DEV\AUX, etc.
  624.  */
  625.     if (strlen(path) == 4 && path[3] == ':') {
  626.         strncpy(newpath+7, path, 3);
  627.         path = newpath;
  628.     }
  629.  
  630. /* first, check for a drive letter */
  631. /* BUG: a '\' at the start of a symbolic link is relative to the current
  632.  * drive of the process, not the drive the link is located on
  633.  */
  634.     if (path[1] == ':') {
  635.         c = path[0];
  636.         if (c >= 'a' && c <= 'z')
  637.             drv = c - 'a';
  638.         else if (c >= 'A' && c <= 'Z')
  639.             drv = c - 'A';
  640.         else
  641.             goto nodrive;
  642.         path += 2;
  643.         i = 1;        /* remember that we saw a drive letter */
  644.     } else {
  645. nodrive:
  646.         drv = curproc->curdrv;
  647.     }
  648.  
  649. /* see if the path is rooted from '\\' */
  650.     if (DIRSEP(*path)) {
  651.         while(DIRSEP(*path))path++;
  652.         dup_cookie(&dir, &curproc->root[drv]);
  653.     } else {
  654.         if (i)    {    /* an explicit drive letter was given */
  655.             dup_cookie(&dir, &curproc->curdir[drv]);
  656.         }
  657.         else
  658.             dup_cookie(&dir, relto);
  659.     }
  660.  
  661.     if (!dir.fs) {
  662.         changedrv(dir.dev);
  663.         dup_cookie(&dir, &curproc->root[drv]);
  664.     }
  665.  
  666.     if (!dir.fs) {
  667.         DEBUG(("path2cookie: no file system: returning EDRIVE"));
  668.         return EDRIVE;
  669.     }
  670.  
  671.     /* here's where we come when we've gone across a mount point */
  672.     
  673. restart_mount:
  674.  
  675.     if (!*path) {        /* nothing more to do */
  676. PATH2COOKIE_DB(("relpath2cookie: no more path, returning 0"));
  677.         *res = dir;
  678.         return 0;
  679.     }
  680.  
  681. /* see if there has been a disk change; if so, return E_CHNG.
  682.  * path2cookie will restart the search automatically; other functions
  683.  * that call relpath2cookie directly will have to fail gracefully
  684.  */
  685.     if ((r = disk_changed(dir.dev)) != 0) {
  686.         release_cookie(&dir);
  687.         if (r > 0) r = E_CHNG;
  688. PATH2COOKIE_DB(("relpath2cookie: returning %d", r));
  689.         return r;
  690.     }
  691.  
  692.  
  693.     if (dir.fs->fsflags & FS_KNOPARSE) {
  694.         if (!dolast) {
  695. PATH2COOKIE_DB(("fs is a KNOPARSE, nothing to do"));
  696.             strncpy(lastname, path, PATH_MAX-1);
  697.             lastname[PATH_MAX - 1] = 0;
  698.             r = 0;
  699.             *res = dir;
  700.         } else {
  701. PATH2COOKIE_DB(("fs is a KNOPARSE, calling lookup"));
  702.             r = (*dir.fs->lookup)(&dir, path, res);
  703.             if (r == EMOUNT) {    /* hmmm... a ".." at a mount point, maybe */
  704.                 fcookie mounteddir;
  705.                 r = (*dir.fs->root)(dir.dev, &mounteddir);
  706.                 if (r == 0 && drv == UNIDRV) {
  707.                     if (dir.fs == mounteddir.fs &&
  708.                         dir.index == mounteddir.index &&
  709.                         dir.dev == mounteddir.dev) {
  710.                         release_cookie(&dir);
  711.                         release_cookie(&mounteddir);
  712.                         dup_cookie(&dir, &curproc->root[UNIDRV]);
  713.                         TRACE(("path2cookie: restarting from mount point"));
  714.                         goto restart_mount;
  715.                     }
  716.                 } else {
  717.                     if (r == 0)
  718.                         release_cookie(&mounteddir);
  719.                     r = 0;
  720.                 }
  721.             }
  722.             release_cookie(&dir);
  723.         }
  724.         PATH2COOKIE_DB(("relpath2cookie: returning %ld", r));
  725.         return r;
  726.     }
  727.  
  728.  
  729. /* parse all but (possibly) the last component of the path name */
  730. /* rules here: at the top of the loop, &dir is the cookie of
  731.  * the directory we're in now, xattr is its attributes, and res is unset
  732.  * at the end of the loop, &dir is unset, and either r is nonzero
  733.  * (to indicate an error) or res is set to the final result
  734.  */
  735.     r = (dir.fs->getxattr)(&dir, &xattr);
  736.     if (r) {
  737.         DEBUG(("couldn't get directory attributes"));
  738.         release_cookie(&dir);
  739.         return EINTRN;
  740.     }
  741.  
  742.     while (*path) {
  743.  
  744.     /* now we must have a directory, since there are more things in the path */
  745.         if ((xattr.mode & S_IFMT) != S_IFDIR) {
  746. PATH2COOKIE_DB(("relpath2cookie: not a directory, returning EPTHNF"));
  747.             release_cookie(&dir);
  748.             r = EPTHNF;
  749.             break;
  750.         }
  751.     /* we must also have search permission for the directory */
  752.         if (denyaccess(&xattr, S_IXOTH)) {
  753.             DEBUG(("search permission in directory denied"));
  754.             release_cookie(&dir);
  755.             r = EPTHNF;
  756.             break;
  757.         }
  758.  
  759.     /* if there's nothing left in the path, we can break here */
  760.         if (!*path) {
  761. PATH2COOKIE_DB(("relpath2cookie: no more path, breaking (1)"));
  762.             *res = dir;
  763.             break;
  764.         }
  765.     /* next, peel off the next name in the path */
  766.         len = 0;
  767.         s = lastname;
  768.         c = *path;
  769.         while (c && !DIRSEP(c)) {
  770.             if (len++ < PATH_MAX)
  771.                 *s++ = c;
  772.             c = *++path;
  773.         }
  774.         *s = 0;
  775.  
  776.     /* if there are no more names in the path, and we don't want
  777.      * to actually look up the last name, then we're done
  778.      */
  779.         if (dolast == 0 && !*path) {
  780.             *res = dir;
  781. PATH2COOKIE_DB(("relpath2cookie: no more path, breaking (2)"));
  782.             break;
  783.         }
  784.  
  785.  
  786.     /* 
  787.      * skip trailing slashes
  788.      */
  789.         while (DIRSEP(*path)) path++;
  790.  
  791. PATH2COOKIE_DB(("relpath2cookie: looking up [%s]", lastname));
  792.  
  793.         r = (*dir.fs->lookup)(&dir, lastname, res);
  794.         if (r == EMOUNT) {
  795.             fcookie mounteddir;
  796.             r = (*dir.fs->root)(dir.dev, &mounteddir);
  797.             if (r == 0 && drv == UNIDRV) {
  798.                 if (samefile(&dir, &mounteddir)) {
  799.                     release_cookie(&dir);
  800.                     release_cookie(&mounteddir);
  801.                     dup_cookie(&dir, &curproc->root[UNIDRV]);
  802.                     TRACE(("path2cookie: restarting from mount point"));
  803.                     goto restart_mount;
  804.                 } else if (r == 0) {
  805.                     r = EINTRN;
  806.                     release_cookie(&mounteddir);
  807.                     release_cookie(&dir);
  808.                     break;
  809.                 }
  810.             } else if (r == 0) {
  811.                 release_cookie(&mounteddir);
  812.             } else {
  813.                 release_cookie(&dir);
  814.                 break;
  815.             }
  816.         } else if (r) {
  817.             if (r == EFILNF && *path) {
  818.             /* the "file" we didn't find was treated as a directory */
  819.                 r = EPTHNF;
  820.             }
  821.             release_cookie(&dir);
  822.             break;
  823.         }
  824.  
  825.     /* check for a symbolic link */
  826.         r = (res->fs->getxattr)(res, &xattr);
  827.         if (r != 0) {
  828.             DEBUG(("path2cookie: couldn't get file attributes"));
  829.             release_cookie(&dir);
  830.             release_cookie(res);
  831.             break;
  832.         }
  833.  
  834.     /* if the file is a link, and we're following links, follow it */
  835.         if ( (xattr.mode & S_IFMT) == S_IFLNK && (*path || dolast > 1)) {
  836.             r = (res->fs->readlink)(res, linkstuff, PATH_MAX);
  837.             release_cookie(res);
  838.             if (r) {
  839.                 DEBUG(("error reading symbolic link"));
  840.                 release_cookie(&dir);
  841.                 break;
  842.             }
  843.             r = relpath2cookie(&dir, linkstuff, follow_links, res,
  844.                         depth+1);
  845.             release_cookie(&dir);
  846.             if (r) {
  847.                 DEBUG(("error following symbolic link"));
  848.                 break;
  849.             }
  850.             dir = *res;
  851.             (void)(res->fs->getxattr)(res, &xattr);
  852.         } else {
  853.             release_cookie(&dir);
  854.             dir = *res;
  855.         }
  856.     }
  857.  
  858.     PATH2COOKIE_DB(("relpath2cookie: returning %ld", r));
  859.     return r;
  860. }
  861.  
  862. #define MAX_TRYS 8
  863.  
  864. long
  865. path2cookie(path, lastname, res)
  866.     const char *path;
  867.     char *lastname;
  868.     fcookie *res;
  869. {
  870.     fcookie *dir;
  871.     long r;
  872. /* AHDI sometimes will keep insisting that a media change occured;
  873.  * we limit the number of retrys to avoid hanging the system
  874.  */
  875.     int trycnt = 0;
  876.  
  877.     dir = &curproc->curdir[curproc->curdrv];
  878.  
  879.     do {
  880.         r = relpath2cookie(dir, path, lastname, res, 0);
  881.         if (r == E_CHNG)
  882.             DEBUG(("path2cookie: restarting due to media change"));
  883.     } while (r == E_CHNG && trycnt++ < MAX_TRYS);
  884.  
  885.     return r;
  886. }
  887.  
  888. /*
  889.  * release_cookie: tell the file system owner that a cookie is no
  890.  * longer in use by the kernel
  891.  */
  892. void
  893. release_cookie(fc)
  894.     fcookie *fc;
  895. {
  896.     FILESYS *fs;
  897.  
  898.     if (fc) {
  899.         fs = fc->fs;
  900.         if (fs && fs->release) {
  901.             (void)(*fs->release)(fc);
  902.         }
  903.     }
  904. }
  905.  
  906. /*
  907.  * Make a new cookie (newc) which is a duplicate of the old cookie
  908.  * (oldc). This may be something the file system is interested in,
  909.  * so we give it a chance to do the duplication; if it doesn't
  910.  * want to, we just copy.
  911.  */
  912.  
  913. void
  914. dup_cookie(newc, oldc)
  915.     fcookie *newc, *oldc;
  916. {
  917.     FILESYS *fs = oldc->fs;
  918.  
  919.     if (fs && fs->release && fs->dupcookie) {
  920.         (void)(*fs->dupcookie)(newc, oldc);
  921.     } else {
  922.         *newc = *oldc;
  923.     }
  924. }
  925.  
  926. /*
  927.  * new_fileptr, dispose_fileptr: allocate (deallocate) a file pointer
  928.  */
  929.  
  930. FILEPTR *
  931. new_fileptr()
  932. {
  933.     FILEPTR *f;
  934.  
  935.     if ((f = flist) != 0) {
  936.         flist = f->next;
  937.         f->next = 0;
  938.         return f;
  939.     }
  940.     f = kmalloc(SIZEOF(FILEPTR));
  941.     if (!f) {
  942.         FATAL("new_fileptr: out of memory");
  943.     }
  944.     else {
  945.         f->next = 0;
  946.     }
  947.     return f;
  948. }
  949.  
  950. void
  951. dispose_fileptr(f)
  952.     FILEPTR *f;
  953. {
  954.     if (f->links != 0) {
  955.         FATAL("dispose_fileptr: f->links == %d", f->links);
  956.     }
  957.     f->next = flist;
  958.     flist = f;
  959. }
  960.  
  961. /*
  962.  * denyshare(list, f): "list" points at the first FILEPTR in a
  963.  * chained list of open FILEPTRS referring to the same file;
  964.  * f is a newly opened FILEPTR. Every FILEPTR in the given list is
  965.  * checked to see if its "open" mode (in list->flags) is compatible with
  966.  * the open mode in f->flags. If not (for example, if f was opened with
  967.  * a "read" mode and some other file has the O_DENYREAD share mode),
  968.  * then 1 is returned. If all the open FILEPTRs in the list are
  969.  * compatible with f, then 0 is returned.
  970.  * This is not as complicated as it sounds. In practice, just keep a
  971.  * list of open FILEPTRs attached to each file, and put something like
  972.  *     if (denyshare(thisfile->openfileptrlist, newfileptr))
  973.  *        return EACCDN;
  974.  * in the device open routine.
  975.  */
  976.  
  977. int ARGS_ON_STACK 
  978. denyshare(list, f)
  979.     FILEPTR *list, *f;
  980. {
  981.     int newrm, newsm;    /* new read and sharing mode */
  982.     int oldrm, oldsm;    /* read and sharing mode of already opened file */
  983.     int i;
  984.  
  985.     newrm = f->flags & O_RWMODE;
  986.     newsm = f->flags & O_SHMODE;
  987.  
  988. /*
  989.  * O_EXEC gets treated the same as O_RDONLY for our purposes
  990.  */
  991.     if (newrm == O_EXEC) newrm = O_RDONLY;
  992.  
  993. /* New meaning for O_COMPAT: deny write access to all _other_
  994.  * processes.
  995.  */
  996.  
  997.     for ( ; list; list = list->next) {
  998.         oldrm = list->flags & O_RWMODE;
  999.         if (oldrm == O_EXEC) oldrm = O_RDONLY;
  1000.         oldsm = list->flags & O_SHMODE;
  1001.         if (oldsm == O_DENYW || oldsm == O_DENYRW) {
  1002.              if (newrm != O_RDONLY) {
  1003.                 DEBUG(("write access denied"));
  1004.                 return 1;
  1005.             }
  1006.         }
  1007.         if (oldsm == O_DENYR || oldsm == O_DENYRW) {
  1008.             if (newrm != O_WRONLY) {
  1009.                 DEBUG(("read access denied"));
  1010.                 return 1;
  1011.             }
  1012.         }
  1013.         if (newsm == O_DENYW || newsm == O_DENYRW) {
  1014.             if (oldrm != O_RDONLY) {
  1015.                 DEBUG(("couldn't deny writes"));
  1016.                 return 1;
  1017.             }
  1018.         }
  1019.         if (newsm == O_DENYR || newsm == O_DENYRW) {
  1020.             if (oldrm != O_WRONLY) {
  1021.                 DEBUG(("couldn't deny reads"));
  1022.                 return 1;
  1023.             }
  1024.         }
  1025. /* If either sm == O_COMPAT, then we check to make sure
  1026.    that the file pointers are owned by the same process (O_COMPAT means
  1027.    "deny writes to any other processes"). This isn't quite the same
  1028.    as the Atari spec, which says O_COMPAT means "deny access to other
  1029.    processes." We should fix the spec.
  1030.  */
  1031.         if ((newsm == O_COMPAT && newrm != O_RDONLY && oldrm != O_RDONLY) ||
  1032.             (oldsm == O_COMPAT && newrm != O_RDONLY)) {
  1033.             for (i = MIN_HANDLE; i < MAX_OPEN; i++) {
  1034.                 if (curproc->handle[i] == list)
  1035.                     goto found;
  1036.             }
  1037.         /* old file pointer is not open by this process */
  1038.             DEBUG(("O_COMPAT file was opened for writing by another process"));
  1039.             return 1;
  1040.         found:
  1041.             ;    /* everything is OK */
  1042.         }
  1043.     }
  1044.     return 0;
  1045. }
  1046.  
  1047. /*
  1048.  * denyaccess(XATTR *xattr, unsigned perm): checks to see if the access
  1049.  * specified by perm (which must be some combination of S_IROTH, S_IWOTH,
  1050.  * and S_IXOTH) should be granted to the current process
  1051.  * on a file with the given extended attributes. Returns 0 if access
  1052.  * by the current process is OK, 1 if not.
  1053.  */
  1054.  
  1055. int
  1056. denyaccess(xattr, perm)
  1057.     XATTR *xattr;
  1058.     unsigned perm;
  1059. {
  1060.     unsigned mode;
  1061.  
  1062. /* the super-user can do anything! */
  1063.     if (curproc->euid == 0)
  1064.         return 0;
  1065.  
  1066.     mode = xattr->mode;
  1067.     if (curproc->euid == xattr->uid)
  1068.         perm = perm << 6;
  1069.     else if (curproc->egid == xattr->gid)
  1070.         perm = perm << 3;
  1071.     if ((mode & perm) != perm) return 1;    /* access denied */
  1072.     return 0;
  1073. }
  1074.  
  1075. /*
  1076.  * Checks a lock against a list of locks to see if there is a conflict.
  1077.  * This is a utility to be used by file systems, somewhat like denyshare
  1078.  * above. Returns 0 if there is no conflict, or a pointer to the
  1079.  * conflicting LOCK structure if there is.
  1080.  *
  1081.  * Conflicts occur for overlapping locks if the process id's are
  1082.  * different and if at least one of the locks is a write lock.
  1083.  *
  1084.  * NOTE: we assume before being called that the locks have been converted
  1085.  * so that l_start is absolute. not relative to the current position or
  1086.  * end of file.
  1087.  */
  1088.  
  1089. LOCK * ARGS_ON_STACK 
  1090. denylock(list, lck)
  1091.     LOCK *list, *lck;
  1092. {
  1093.     LOCK *t;
  1094.     unsigned long tstart, tend;
  1095.     unsigned long lstart, lend;
  1096.     int pid = curproc->pid;
  1097.     int ltype;
  1098.  
  1099.     ltype = lck->l.l_type;
  1100.     lstart = lck->l.l_start;
  1101.  
  1102.     if (lck->l.l_len == 0)
  1103.         lend = 0xffffffffL;
  1104.     else
  1105.         lend = lstart + lck->l.l_len - 1;
  1106.  
  1107.     for (t = list; t; t = t->next) {
  1108.         tstart = t->l.l_start;
  1109.         if (t->l.l_len == 0)
  1110.             tend = 0xffffffffL;
  1111.         else
  1112.             tend = tstart + t->l.l_len - 1;
  1113.  
  1114.     /* look for overlapping locks */
  1115.         if (tstart <= lstart && tend >= lstart && t->l.l_pid != pid &&
  1116.             (ltype == F_WRLCK || t->l.l_type == F_WRLCK))
  1117.             break;
  1118.         if (lstart <= tstart && lend >= tstart && t->l.l_pid != pid &&
  1119.             (ltype == F_WRLCK || t->l.l_type == F_WRLCK))
  1120.             break;
  1121.     }
  1122.     return t;
  1123. }
  1124.  
  1125. /*
  1126.  * check to see that a file is a directory, and that write permission
  1127.  * is granted; return an error code, or 0 if everything is ok.
  1128.  */
  1129. long
  1130. dir_access(dir, perm)
  1131.     fcookie *dir;
  1132.     unsigned perm;
  1133. {
  1134.     XATTR xattr;
  1135.     long r;
  1136.  
  1137.     r = (*dir->fs->getxattr)(dir, &xattr);
  1138.     if (r) {
  1139.         DEBUG(("dir_access: file system returned %ld", r));
  1140.         return r;
  1141.     }
  1142.     if ( (xattr.mode & S_IFMT) != S_IFDIR ) {
  1143.         DEBUG(("file is not a directory"));
  1144.         return EPTHNF;
  1145.     }
  1146.     if (denyaccess(&xattr, perm)) {
  1147.         DEBUG(("no permission for directory"));
  1148.         return EACCDN;
  1149.     }
  1150.     return 0;
  1151. }
  1152.  
  1153. /*
  1154.  * returns 1 if the given name contains a wildcard character 
  1155.  */
  1156.  
  1157. int
  1158. has_wild(name)
  1159.     const char *name;
  1160. {
  1161.     char c;
  1162.  
  1163.     while ((c = *name++) != 0) {
  1164.         if (c == '*' || c == '?') return 1;
  1165.     }
  1166.     return 0;
  1167. }
  1168.  
  1169. /*
  1170.  * void copy8_3(dest, src): convert a file name (src) into DOS 8.3 format
  1171.  * (in dest). Note the following things:
  1172.  * if a field has less than the required number of characters, it is
  1173.  * padded with blanks
  1174.  * a '*' means to pad the rest of the field with '?' characters
  1175.  * special things to watch for:
  1176.  *    "." and ".." are more or less left alone
  1177.  *    "*.*" is recognized as a special pattern, for which dest is set
  1178.  *    to just "*"
  1179.  * Long names are truncated. Any extensions after the first one are
  1180.  * ignored, i.e. foo.bar.c -> foo.bar, foo.c.bar->foo.c.
  1181.  */
  1182.  
  1183. void
  1184. copy8_3(dest, src)
  1185.     char *dest;
  1186.     const char *src;
  1187. {
  1188.     char fill = ' ', c;
  1189.     int i;
  1190.  
  1191.     if (src[0] == '.') {
  1192.         if (src[1] == 0) {
  1193.             strcpy(dest, ".       .   ");
  1194.             return;
  1195.         }
  1196.         if (src[1] == '.' && src[2] == 0) {
  1197.             strcpy(dest, "..      .   ");
  1198.             return;
  1199.         }
  1200.     }
  1201.     if (src[0] == '*' && src[1] == '.' && src[2] == '*' && src[3] == 0) {
  1202.         dest[0] = '*';
  1203.         dest[1] = 0;
  1204.         return;
  1205.     }
  1206.  
  1207.     for (i = 0; i < 8; i++) {
  1208.         c = *src++;
  1209.         if (!c || c == '.') break;
  1210.         if (c == '*') {
  1211.             fill = c = '?';
  1212.         }
  1213.         *dest++ = toupper(c);
  1214.     }
  1215.     while (i++ < 8) {
  1216.         *dest++ = fill;
  1217.     }
  1218.     *dest++ = '.';
  1219.     i = 0;
  1220.     fill = ' ';
  1221.     while (c && c != '.')
  1222.         c = *src++;
  1223.  
  1224.     if (c) {
  1225.         for( ;i < 3; i++) {
  1226.             c = *src++;
  1227.             if (!c || c == '.') break;
  1228.             if (c == '*')
  1229.                 c = fill = '?';
  1230.             *dest++ = toupper(c);
  1231.         }
  1232.     }
  1233.     while (i++ < 3)
  1234.         *dest++ = fill;
  1235.     *dest = 0;
  1236. }
  1237.  
  1238. /*
  1239.  * int pat_match(name, patrn): returns 1 if "name" matches the template in
  1240.  * "patrn", 0 if not. "patrn" is assumed to have been expanded in 8.3
  1241.  * format by copy8_3; "name" need not be. Any '?' characters in patrn
  1242.  * will match any character in name. Note that if "patrn" has a '*' as
  1243.  * the first character, it will always match; this will happen only if
  1244.  * the original pattern (before copy8_3 was applied) was "*.*".
  1245.  *
  1246.  * BUGS: acts a lot like the silly TOS pattern matcher.
  1247.  */
  1248.  
  1249. int
  1250. pat_match(name, template)
  1251.     const char *name, *template;
  1252. {
  1253.     register char *s, c;
  1254.     char expname[TOS_NAMELEN+1];
  1255.  
  1256.     if (*template == '*') return 1;
  1257.     copy8_3(expname, name);
  1258.  
  1259.     s = expname;
  1260.     while ((c = *template++) != 0) {
  1261.         if (c != *s && c != '?')
  1262.             return 0;
  1263.         s++;
  1264.     }
  1265.     return 1;
  1266. }
  1267.  
  1268. /*
  1269.  * int samefile(fcookie *a, fcookie *b): returns 1 if the two cookies
  1270.  * refer to the same file or directory, 0 otherwise
  1271.  */
  1272.  
  1273. int
  1274. samefile(a, b)
  1275.     fcookie *a, *b;
  1276. {
  1277.     if (a->fs == b->fs && a->dev == b->dev && a->index == b->index)
  1278.         return 1;
  1279.     return 0;
  1280. }
  1281.